package com.kkb.aop;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/*注解方式实现AOP*/
@Component
@Aspect
public class MyAspect {

    /**
     * 当较多的通知增强方法使用相同的 execution 切入点表达式时，编写、维护均较为麻烦。
     * AspectJ 提供了@Pointcut 注解，用于定义 execution 切入点表达式。
     * 其用法是，将@Pointcut 注解在一个方法之上，以后所有的 execution 的 value 属性值均
     * 可使用该方法名作为切入点。代表的就是@Pointcut 定义的切入点。
     * 这个使用@Pointcut 注解方法一般使用 private 的标识方法，即没有实际作用的方法。
     */
    @Pointcut("execution(* com.kkb.service..*.*(..))")
    private void pointCut(){

    }

    @Pointcut("execution(* com.kkb.service..*.add*(..))")
    private void pointCut2(){

    }

    /*声明前置通知*/
    @Before("pointCut()")
    public void before(JoinPoint jp){
        System.out.println("前置通知：在目标方法执行之前被调用的通知");
        String name = jp.getSignature().getName();
        System.out.println("拦截的方法名称："+name);
        Object[] args = jp.getArgs();
        System.out.println("方法的参数格式："+args.length);
        System.out.println("方法参数列表：");
        for(Object arg : args) {
            System.out.println("\t"+arg);
        }
    }

    /**
     * AfterReturning 注解声明后置通知
     * value： 表示切入点表达式
     * returning 属性表示 返回的结果，如果需要的话可以在后置通知的方法中修改结果
     * @param result
     * @return
     */
    @AfterReturning(value = "pointCut2()",returning = "result")
    public Object afterReturn(Object result){
        if (result!=null){
            boolean res = (boolean) result;
            if (res){
                result = false;
            }
        }
        System.out.println("后置通知：在目标方法执行之后被调用的通知,result="+result);

        return result;
    }


    /**
     * Around 注解声明环绕通知
     * ProceedingJoinPoint 中的proceed方法表示目标方法被执行
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕方法---目标方法的执行之前");
        Object proceed = pjp.proceed();
        System.out.println("环绕方法---目标方法的执行之后");
        return proceed;
    }

    /**
     * AfterThrowing 注解声明异常通知方法
     * value： 表示切入点表达式
     * returning 属性表示 返回的结果，如果需要的话可以在后置通知的方法中修改结果
     * @param jp
     * @param ex
     */
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void exception(JoinPoint jp,Throwable ex){
        //一般会把异常发生的时间、位置、原有都记录下来
        System.out.println("异常通知：在目标方法执行出现异常的时候才会别调用的通知，否则不 执行");
        System.out.println(jp.getSignature()+"方法出现异常，异常信息 是："+ex.getMessage());

    }

    /** After 注解声明为最终通知
     */
    @After( "pointCut()")
    public void myFinally() {
        System.out.println("最终通知：无论是否出现异常都是最后被调用的通知");
    }
}
